﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace ALinq.Mapping
{
    /// <summary>
    /// Serializes DatabaseMapping objects into XML documents
    /// </summary>          
    public static class DatabaseMappingSerializer
    {
        class XmlMappingWriter //: ModelMappingVisitor
        {
            private const string DATABASE = "Database";
            private const string TABLE = "Table";
            private const string TYPE = "Type";
            private const string ASSOCIATION = "Association";
            private const string COLUMN = "Column";

            private const string Namespace = "http://schemas.microsoft.com/linqtosql/mapping/2007";
            private XmlDocument doc;
 
            public XmlMappingWriter(XmlDocument doc)
            {
                this.doc = doc;
            }

            void SetAttributes(ModelMapping modelMapping, XmlElement element)
            {
                foreach (var attr in modelMapping.Attributes)
                {
                    var name = attr.Key;
                    var value = attr.Value;
                    element.SetAttribute(name, value.ToString());
                }
            }

            internal XmlElement VisitDatabase(DatabaseMapping databaseMapping)
            {
                var databaseElement = this.doc.CreateElement(DATABASE, Namespace);
                this.doc.AppendChild(databaseElement);
                SetAttributes(databaseMapping, databaseElement);

                //base.VisitDatabase(databaseMapping);
                foreach (var table in databaseMapping.Tables)
                {
                    var tableElement = VisitTable(table);
                    databaseElement.AppendChild(tableElement);
                }

                return databaseElement;
            }

            private XmlElement VisitTable(TableMapping tableMapping)
            {
                var tableElement = this.doc.CreateElement(TABLE, Namespace);
                SetAttributes(tableMapping, tableElement);

                var typeElement = VisitType(tableMapping.RowType);
                tableElement.AppendChild(typeElement);

                return tableElement;
            }

            private XmlElement VisitType(TypeMapping typeMapping)
            {
                var typeElement = this.doc.CreateElement(TYPE, Namespace);

                //=======================================================
                // 设置 InheritanceCode 的默认值
                if (typeMapping.IsInheritanceDefault && typeMapping.InheritanceCode == null)
                    typeMapping.InheritanceCode = typeMapping.Type.Name;

                //=======================================================

                SetAttributes(typeMapping, typeElement);
                foreach (var col in typeMapping.Columns)
                {
                    var columnElement = VisitColumn(col);
                    typeElement.AppendChild(columnElement);
                }

                foreach(var assoc in typeMapping.Associations)
                {
                    var assocElement = VisitAssociation(assoc);
                    typeElement.AppendChild(assocElement);
                }

                foreach(var subType in typeMapping.DerivedTypes)
                {
                    var subTypeElement = VisitType(subType);
                    typeElement.AppendChild(subTypeElement);
                }

                return typeElement;
            }

            private XmlElement VisitColumn(ColumnMapping columnMapping)
            {
                var element = this.doc.CreateElement(COLUMN, Namespace);
                SetAttributes(columnMapping, element);

                return element;
            }

            private XmlElement VisitAssociation(AssociationMapping association)
            {
                var element = this.doc.CreateElement(ASSOCIATION, Namespace);
                SetAttributes(association, element);

                return element;
            }
        }

        class ModelValidate : ModelMappingVisitor
        {
            public override void VisitType(TypeMapping typeMapping)
            {
                //验证必须继承树中，必须有一个 InheritanceDefalt 为 true
                //Code 
                base.VisitType(typeMapping);
            }
        }

        ///<summary>
        /// Serializes the specified DatabaseMapping into the XML document.
        ///</summary>
        ///<param name="databaseMapping">An XML document contains the serialize result for database-mapping.</param>
        ///<returns>The DatabaseMapping object to serialize.</returns>
        public static XmlDocument Serialize(DatabaseMapping databaseMapping)
        {
            var doc = new XmlDocument();
            new XmlMappingWriter(doc).VisitDatabase(databaseMapping);


            return doc;
        }


    }
}
